package main

import (
	"strconv"
	"sync"

	"github.com/gin-gonic/gin"
)

var (
	// 余票 直接用 map 模拟
	tickets = make(map[int]Ticket)
	mu      sync.Mutex
)

type Ticket struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Stock int    `json:"stock"`
}

type TicketList struct {
	Data []Ticket `json:"data"`
}

type UpdateTicketRequest struct {
	ID  int `json:"id"`
	Num int `json:"num"`
}

type UpdateTicketResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

func init() {
	// 测试数据 用 map 模拟
	tickets[1] = Ticket{ID: 1, Name: "train", Stock: 100}
	tickets[2] = Ticket{ID: 2, Name: "plane", Stock: 50}
}

func main() {
	r := gin.Default()

	r.GET("/ticket/:id", getTicketByID)
	r.GET("/ticket", getTicketList)
	r.PUT("/ticket", updateTicket)

	println("Server started at :8088")
	r.Run(":8088")
}

func getTicketByID(c *gin.Context) {
	idStr := c.Param("id")
	id, _ := strconv.Atoi(idStr)

	mu.Lock()
	defer mu.Unlock()

	if ticket, ok := tickets[id]; ok {
		c.JSON(200, ticket)
		return
	}
	c.AbortWithStatus(404)
}

func getTicketList(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	pageSize, _ := strconv.Atoi(c.Query("pageSize"))

	mu.Lock()
	defer mu.Unlock()

	allTickets := make([]Ticket, 0)
	for _, t := range tickets {
		allTickets = append(allTickets, t)
	}

	start := (page - 1) * pageSize
	end := page * pageSize
	if start >= len(allTickets) {
		c.JSON(200, []Ticket{})
		return
	}
	if end > len(allTickets) {
		end = len(allTickets)
	}

	c.JSON(200, TicketList{Data: allTickets[start:end]})
}

func updateTicket(c *gin.Context) {
	var req UpdateTicketRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.AbortWithStatus(400)
		return
	}

	mu.Lock()
	defer mu.Unlock()

	if ticket, ok := tickets[req.ID]; ok {
		if ticket.Stock >= req.Num {
			ticket.Stock -= req.Num
			tickets[req.ID] = ticket
			c.JSON(200, &UpdateTicketResponse{
				Success: true,
				Message: "成功抢票",
			})
			return
		}
		c.JSON(400, &UpdateTicketResponse{
			Success: false,
			Message: "余票不足",
		})
		return
	}
	c.AbortWithStatus(404)
}
